
// 获取一个非空的span
Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    // 查看当前的SpanList中是否存在非空的span
    Span* it = list.Begin();

    while(it != list.End())
    {
        if(it->_freeList != nullptr)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }

    // 走到这说明需要从page cache中获取内存

    // 解除central cache对应的桶锁，方便thread cache释放内存回来不会被阻塞住
    list._mtx.unlock();

    // 加上page cache的大锁
    PageCache::GetInstance()->_pageMtx.lock();

    // 获取一个K页的span
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    span->_isUse = true;
    span->_objSize = size;

    // 解除page cache的大锁
    PageCache::GetInstance()->_pageMtx.unlock(); // page cache 的大锁是在类中定义的，central cache的桶锁是定义在Span List中的

    // 对获取到的span进行切分

    // 先计算出该span的起始地址和结束地址以及所占的字节数
    char* start = (char*)(span->_pageId << PAGE_SHIFT);
    size_t bytes = span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    // 对该span进行切分
    // 先切一块做头，方便尾插
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }

    NextObj(tail) = nullptr;

    // 将切分好的span挂上去，再加锁
    list.PushFront(span);
    list._mtx.lock();

    return span;
}


#include "CentralCache.h"
#include "PageCache.h"

// 类中静态static成员变量在.cpp文件中定义
CentralCache CentralCache::_sInst;


// // 从中心缓存获取一定数量的内存对象给thread cache
// size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
// {
//     assert(size <= MAX_BYTES);
//     size_t index = SizeClass::Index(size);

//     // 加桶锁
//     _spanLists[index]._mtx.lock();

//     // 获取一个非空的span
//     Span* span = CentralCache::GetOneSpan(_spanLists[index], size);
//     assert(span);
//     assert(span->_freeList);

//     // 获取batchNum个内存对象，不够的话，有多少拿多少
//     start = span->_freeList;
//     end = start;
//     size_t i = 0;
//     size_t actualNum = 1;

//     while(i < batchNum - 1 && NextObj(end) != nullptr)
//     {
//         end = NextObj(end);
//         i++;
//         actualNum++;
//     }

//     _freeList = NextObj(end);
//     NextObj(end) = nullptr;
//     span->_useCount += actualNum;

//     // 解桶锁
//     _spanLists[index]._mtx.unlock();

//     return actualNum;
// }



// // 获取一个非空的span
// Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
// {
//     assert(size <= MAX_BYTES);

//     // 查看当前的spanlist中是否还有未分配的span
//     Span* it = list.Begin();

//     while(it != list.End())
//     {
//         if(it->_freeList)
//         {
//             return it;
//         }
//         else
//         {
//             it = it->_next;
//         }
//     }

//     // 走到这说明需要去page cache中申请

//     // 解除桶锁，方便thread cache中释放内存回到central cache不会被阻塞住
//     list._mtx.unlock();

//     // 加上page cache的大锁
//     PageCache::GetInstance()->_pageMtx.lock();

//     // 向page cache获取K页的span
//     Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
//     assert(span);
//     assert(span->_freeList);
//     span->_isUse = true;
//     span->_objSize = size;

//     // 解除page cache的大锁
//     PageCache::GetInstance()->_pageMtx.unlock();

//     // 走到这需要对刚刚获取到的span进行切分

//     // 计算大块内存的起始地址和大块内存的大小
//     char* start = (char*)(span->_pageId << PAGE_SHIFT); // 系统会自动填充起始页的页号？
//     size_t bytes = span->_n << PAGE_SHIFT;
//     char* end = start + bytes;

//     // 把大块内存切成自由链表链接起来
//     // 先切一块下来做头，方便尾插
//     span->_freeList = start;
//     start += size;
//     void* tail = span->_freeList;

//     while(start < end)
//     {
//         NextObj(tail) = start;
//         tail = NextObj(tail);
//         start += size;
//     }

//     NextObj(tail) = nullptr;

//     // 切好span之后，再将其挂到对应的桶里面去，再加锁
//     list.PushFront(span);
//     list._mtx.lock();

//     return span;
// }


// 从中心缓存获取一定数量的内存对象给thread cache
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加桶锁
    _spanLists[index]._mtx.lock();

    // 首先获取一个非空的span
    Span* span = CentralCache::GetInstance()->GetOneSpan(_spanLists[index], size);
    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    end = start;
    size_t i = 0;
    size_t actualNum = 1;

    while(i < batchNum - 1 && NextObj(end) != nullptr)
    {
        i++;
        actualNum++;
        end = NextObj(end);
    }

    span->_freeList = NextObj(end);
    NextObj(end) = nullptr;
    span->_useCount += actualNum;

    // 解桶锁
    _spanLists[index]._mtx.unlock();

    return actualNum;
}


// 获取一个非空的span
Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    // 首先查看当前SpanList中是否存在非空的span可以使用
    Span* it = list.Begin();

    while(it != list.End())
    {
        if(it->_freeList != nullptr)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }

    // 走到这说明需要从page cache中申请

    // 先解除central cache中的桶锁，方便thread cache归还内存对象不会被阻塞
    list._mtx.unlock();

    // 访问page cache时，首先加上page cache的大锁
    PageCache::GetInstance()->_pageMtx.lock();

    // 获取一个K页的span
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    span->_isUse = true;
    span->_objSize = size;

    // 解除page cache的大锁
    PageCache::GetInstance()->_pageMtx.unlock();

    // 首先计算出刚获取到的span的起始和结束地址以及所占的字节数大小
    char* start = (char*)(span->_pageId << PAGE_SHIFT);
    size_t bytes = span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    // 对获取到的span进行切分
    // 首先切一块下来做头，方便尾插
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }

    NextObj(end) = nullptr;

    // 将切好的span挂到central cache中对应的链表中， 然后再加锁
    list.PushFront(span);
    list._mtx.lock();

    return span;
}


#include "CentralCache.h"
#include "PageCache.h"

// 类中静态static成员变量在.cpp文件中定义
CentralCache CentralCache::_sInst;


// 批量获取内存对象给thread cache
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    // 获取一个非空的span
    Span* span = CentralCache::GetInstance()->GetOneSpan(_spanLists[index], size);
    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    end = start;
    size_t actualNum = 1;
    size_t i = 0;

    while(i < batchNum - 1 && NextObj(end) != nullptr)
    {
        i++;
        actualNum++;
        end = NextObj(end);
    }

    span->_freeList = NextObj(end);
    NextObj(end) = nullptr;
    span->_useCount = actualNum;

    // 解除桶锁
    _spanLists[index]._mtx.unlock();

    return actualNum;
}


// 获取一个非空的span
Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    // 首先检查当前的SpanList中是否存在非空的span
    Span* it = list.Begin();

    while(it != list.End())
    {
        if(it->_freeList != nullptr)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }

    // 走到这说明需要从page cache中申请内存了

    // 先将CentralCache中对应的桶锁解掉，以便thread cache还内存回来不会被阻塞
    list._mtx.unlock();

    // 访问page cache之前先将其对应的大锁加上
    PageCache::GetInstance()->_pageMtx.lock();

    // 获取一个K页的span
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    span->_isUse = true;
    span->_objSize = size;

    // 解除page cache对应的大锁
    PageCache::GetInstance()->_pageMtx.unlock();

    // 将获取到的span进行切分
    // 首先计算出他们对应的起始和结束地址以及所占内存空间的大小
    char* start = (char*)(span->_pageId << PAGE_SHIFT);
    size_t bytes = span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    // 先切一块下来做头，方便尾插
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }

    NextObj(tail) = nullptr;

    // 将切分好的span插入a到central cache对应的链表中,然后再加锁
    list.PushFront(span);
    list._mtx.lock();

    return span;
}


#include "ThreadCache.h"
#include "CentralCache.h"


void* ThreadCache::Allocate(size_t size)
{
    assert(size <= MAX_BYTES);

    size_t alignSize = SizeClass::RoundUp(size);
    size_t index = SizeClass::Index(size);

    if(!_freeLists[index].Empty())
    {
        return _freeLists[index].Pop();
    }
    else 
    {
        return ThreadCache::FetchFromCentralCache(index, alignSize);
    }
}

void ThreadCache::Deallocate(void* ptr, size_t size)
{
    assert(ptr);
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    _freeLists[index].Push(ptr);

    if(_freeLists[index].Size() >= _freeLists[index].MaxSize())
    {
        ThreadCache::ListTooLong(_freeLists[index], size);
    }
}

void* ThreadCache::FetchFromCentralCache(size_t index, size_t alignSize)
{
    assert(size <= MAX_BYTES);

    // 慢开始反馈调节算法
    // 1. 最开始不会一次批量申请太多，可能用不完浪费
    // 2. 如果不断有size大小的内存需求，batchNum就会不断变大，直至上限值
    // 3. 小对象一次批量的上限值大
    // 4. 大对象一次批量的上限值小
    size_t batchNum = std::min(_freeLists[index].MaxSize(), SizeClass::NumMoveSize(size));

    if(batchNum == _freeLists[index].MaxSize())
    {
        _freeLists[index].MaxSize() += 1;
    }

    void* start = nullptr;
    void* end = nullptr;
    size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);
    assert(actualNum > 0);

    if(actualNum == 1)
    {
        assert(start == end);
        return start;
    }
    else
    {
        _freeLists[index].PushRange(NextObj(start), end, actualNum - 1);
        return start;
    }
}


void ThreadCache::ListTooLong(FreeList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    void* start = nullptr;
    void* end = nullptr;

    list.PopRange(start, end, list.MaxSize());

    CentralCache::GetInstance()->ReleaseListToSpan(start, size);
}


#include "CentralCache.h"
#include "PageCache.h"

// 类中静态static成员变量在.cpp文件中定义
CentralCache CentralCache::_sInst;


// 获取一定数量的内存对象给thread cache
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    // 获取一个非空的span
    Span* span = CentralCache::GetInstance()->GetOneSpan(_spanLists[index], size);
    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    end = start;
    size_t i = 0;
    size_t actualNum = 1;

    while(i < batchNum - 1 && NextObj(end) != nullptr)
    {
        i++:
        batchNum++;
        end = NextObj(end);
    }

    span->_freeList = NextObj(end);
    NextObj(end) = nullptr;
    span->_useCount = actualNum;

    // 解除桶锁
    _spanLists[index]._mtx.unlock();

    return actualNum;
}


// 获取一个非空的span
Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    // 先判断当前的SpanList是否为空
    Span* it = list.Begin();

    while(it != list.End())
    {
        if(it->_freeList != nullptr)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }


    // 走到这说明需要从page cache中申请内存了
    
    // 解除central cache对应的桶锁，防止thread cache释放内存回来被阻塞住
    list._mtx.unlock();

    // 访问page cache之前需要加上对应的大锁
    PageCache::GetInstance()->_pageMtx.lock();

    // 获取一个K页的span
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    span->_isUse = true;
    span->_objSize = size;

    // 解除page cache对应的大锁
    PageCache::GetInstance()->_pageMtx.unlock();

    // 将获取到的span进行切分
    // 首先计算出其对应的起始和结束地址以及所占内存空间的大小
    char* start = (char*)(span->_pageId << PAGE_SHIFT);
    size_t bytes = span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    // 然后切一块下来做头，方便尾插
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }

    NextObj(tail) = nullptr;

    // 将切分好的内存对象插入到central cache对应的链表中，然后加锁
    list.PushFront(span);
    list._mtx.lock();

    return span;
}



void CentralCache::ReleaseListToSpan(void* start, size_t size)
{
    assert(start);
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    while(start)
    {
        void* next = NextObj(start);

        // 计算对象到span的映射, 并将其插入到其中
        Span* span = PageCache::GetInstance()->MapObjToSpan(start);
        assert(span);
        assert(span->_freeList);
        NextObj(start) = span->_freeList;
        span->_freeList = start;
        span->_useCount -= 1;

        if(span->_useCount == 0)
        {
            // 当_useCount减到0时，将该span还给page cache
            _spanLists[index].Erase(span);
            span->_freeList = nullptr;
            span->_prev = nullptr;
            span->_next = nullptr;

            // 解除桶锁，此时只用page cache一把锁即可
            _spanLists[index]._mtx.unlock();

            PageCache::GetInstance()->_pageMtx.lock();
            PageCache::GetInstance()->ReleaseSpanToPageCache(span);
            PageCache::GetInstance()->_pageMtx.unlock();

            _spanLists[index]._mtx.lock(); 
        }

        start = next;
    }


    // 解除桶锁
    _spanLists[index]._mtx.unlock();
}

#include "CentralCache.h"
#include "PageCache.h"

// 类中静态static成员变量在.cpp文件中定义
CentralCache CentralCache::_sInst;

// // 获取一定数量的内存对象给thread cache
// size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
// {
//     assert(size <= MAX_BYTES);

//     size_t index = SizeClass::Index(size);

//     // 加上桶锁
//     _spanLists[index]._mtx.lock();

//     // 获取一个非空的span
//     Span* span = CentralCache::GetInstance()->GetOneSpan(_spanLists[index], size);
//     assert(span);
//     assert(span->_freeList);

//     start = span->_freeList;
//     end = start;
//     size_t i = 0;
//     size_t actualNum = 1;

//     while(i < batchNum - 1 && NextObj(end) != nullptr)
//     {
//         i++;
//         batchNum++;
//         end = NextObj(end);
//     }

//     span->_freeList = NextObj(end);
//     NextObj(end) = nullptr;
//     span->_useCount = actualNum;

//     // 解除桶锁
//     _spanLists[index]._mtx.unlock();

//     return actualNum;
// }


// // 获取一个非空的span
// Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
// {
//     assert(size <= MAX_BYTES);

//     // 首先查看当前的SpanList中是否存在非空的span
//     Span* it = list.Begin();

//     while(it != list.End())
//     {
//         if(it->_freeList != nullptr)
//         {
//             return it;
//         }
//         else
//         {
//             it = it->_next;
//         }
//     }

//     // 走到这说明需要从page cache获取span

//     // 解除central cache中对应的桶锁，方便thread cache释放内存回来不会阻塞住
//     list._mtx.unlock();

//     // 访问page cache之前先加上其对应的大锁
//     PageCache::GetInstance()->_pageMtx.lock();
//     Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
//     assert(span);
//     assert(span->_freeList);
//     span->_isUse = true;
//     span->_objSize = size;
//     // 解除page cache对应的大锁
//     PageCache::GetInstance()->_pageMtx.unlock();

//     // 将获取到的span进行切分
//     // 首先计算出其对应的起始和结束地址以及所占的内存空间的大小
//     char* start = (char*)(span->_pageId << PAGE_SHIFT);
//     size_t bytes = span->_n << PAGE_SHIFT;
//     char* end = start + bytes;

//     // 先切一块下来做头，方便尾插
//     span->_freeList = start;
//     start += size;
//     void* tail = span->_freeList;

//     while(start < end)
//     {
//         NextObj(tail) = start;
//         tail = NextObj(tail);
//         start += size;
//     }

//     NextObj(tail) = nullptr;

//     // 将切分好的span挂到对应的自由链表桶中，然后加锁
//     list.PushFront(span);
//     list._mtx.lock();

//     return span;
// }



// // void CentralCache::ReleaseListToSpan(void* start, size_t size)
// // {
// //     assert(start);
// //     assert(size <= MAX_BYTES);

// //     size_t index = SizeClass::Index(size);

// //     // 加上桶锁
// //     _spanLists[index]._mtx;

// //     while(start)
// //     {
// //         void* next = NextObj(start);

// //         // 计算该对象对应的span, 并将其插入到其中
// //         Span* span = PageCache::GetInstance()->MapObjToSpan(start);
// //         assert(span);
// //         assert(span->_freeList);
// //         NextObj(start) = span->_freeList;
// //         span->_freeList = start;
// //         span->_useCount -= 1;

// //         // 如果_useCount减为0，即说明分配给thread cache的内存对象全部还回来了，此时该span回收给page cache
// //         if(span->_useCount == 0)
// //         {
// //             _spanLists[index].Erase(span);
// //             span->_freeList = nullptr;
// //             span->_prev = nullptr;
// //             span->_next = nullptr;
// //             // span->_isUse = false; // 这句最好也加上吧？

// //             // 解除桶锁
// //             _spanLists[index]._mtx.unlock();

// //             PageCache::GetInstance()->_pageMtx.lock();
// //             PageCache::GetInstance()->ReleaseSpanToPageCache(span);
// //             PageCache::GetInstance()->_pageMtx.unlock();

// //             // 加上桶锁
// //             _spanLists[index]._mtx.lock();
// //         }

// //         start = next;
// //     }

// //     // 解除桶锁
// //     _spanLists[index]._mtx.unlock();
// // }



// void CentralCache::ReleaseListToSpan(void* start, size_t size)
// {
//     assert(start);
//     assert(size <= MAX_BYTES);

//     size_t index = SizeClass::Index(size);

//     // 加上桶锁
//     _spanLists[index]._mtx.lock();

//     while(start)
//     {
//         void* next = NextObj(start);

//         // 计算该对象对应的span，并将其插入其中
//         Span* span = PageCache::GetInstance()->MapObjToSpan(start);
//         assert(span);
//         assert(span->_freeList);
//         NextObj(start) = span->_freeList;
//         span->_freeList = start;
//         span->_useCount -= 1;

//         // 如果_useCount减至0，表示分配给thread cache的内存对象都已经还回来了, 此时该span也该还给page cache
//         if(span->_useCount == 1)
//         {
//             _spanLists[index].Erase(span);
//             span->_freeList = nullptr;
//             span->_prev = nullptr;
//             span->_next = nullptr;

//             // 解除桶锁，只使用page cache一把大锁即可
//             _spanLists[index]._mtx.unlock();

//             PageCache::GetInstance()->_pageMtx.lock();
//             PageCache::GetInstance()->ReleaseSpanToPageCache(span);
//             PageCache::GetInstance()->_pageMtx.unlock();

//             // 加上桶锁
//             _spanLists[index]._mtx.lock();
//         }

//     }

//     // 解除桶锁
//     _spanLists[index]._mtx.unlock();
// }



// 获取一定数量的内存对象给thread cache
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    // 获取一个非空的span
    Span* span = CentralCache::GetInstance()->GetOneSpan(_spanLists[index], size);
    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    end = start;
    size_t i = 0;
    size_t actualNum = 1;

    while(i < batchNum - 1 && NextObj(end) != nullptr)
    {
        i++;
        actualNum++;
        end = NextObj(end);
    }

    span->_freeList = NextObj(end);
    NextObj(end) = nullptr;
    span->_useCount = actualNum;

    // 解除桶锁
    _spanLists[index]._mtx.unlock();

    return actualNum;
}


Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    // 首先在当前的SpanList中查看是否有非空的span
    Span* it = list.Begin();

    while(it != list.End())
    {
        if(it->_freeList != nullptr)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }

    // 走到这说明需要从page cache中获取span

    // 解除central cache中对应的桶锁
    list._mtx.unlock();

    // 访问page cache之前需要加上对应的大锁
    PageCache::GetInstance()->_pageMtx.lock();

    // 获取一个K页的span
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    span->_objSize = size;
    span->_isUse = true;

    // 解除大锁
    PageCache::GetInstance()->_pageMtx.unlock();

    // 切分刚获取到的span
    // 首先计算出其对应的起始和结束地址以及所占的空间大小
    char* start = (char*)(span->_pageId << PAGE_SHIFT);
    size_t bytes = span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    // 先切一块下来做头，方便尾插
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }

    NextObj(tail) = nullptr;

    // 将切分好的span挂到对应的链表上, 然后再加锁
    list.PushFront(span);
    list._mtx.lock();

    return span;
}


void CentralCache::ReleaseListToSpan(void* start, size_t size)
{
    assert(start);
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    while(start)
    {
        void* next = NextObj(start);

        // 首先计算该对象对应的span, 并将其插入到其中
        Span* span = PageCache::GetInstance()->MapObjToSpan(start);
        assert(span);
        assert(span->_freeList);
        NextObj(start) = span->_freeList;
        span->_freeList = start;
        span->_useCount -= 1;

        if(span->_useCount == 0)
        {
            _spanLists[index].Erase(span);
            span->_freeList = nullptr;
            span->_prev = nullptr;
            span->_next = nullptr;

            // 解除桶锁，此时只用page cache一把大锁即可
            _spanLists[index]._mtx.unlock();

            PageCache::GetInstance()->_pageMtx.lock();
            PageCache::GetInstance()->ReleaseSpanToPageCache(span);
            PageCache::GetInstance()->_pageMtx.unlock();

            // 加上桶锁
            _spanLists[index]._mtx.lock();
        }
    }

    // 解除桶锁
    _spanLists[index]._mtx.unlock();
}




// 获取一定数量的内存对象给thread cache
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    // 获取一个非空的span
    Span* span = CentralCache::GetInstance()->GetOneSpan(_spanLists[index], size);
    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    end = start;
    size_t i = 0;
    size_t actualNum = 1;

    while(i < batchNum - 1 && NextObj(end) != nullptr)
    {
        i++;
        actualNum++;
        end = NextObj(end);
    }

    span->_freeList = NextObj(end);
    NextObj(end) = nullptr;
    span->_useCount = actualNum;

    // 解除桶锁
    _spanLists[index]._mtx.unlock();

    return actualNum;
}


// 获取一个非空的span
Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    // 先查看当前的SpanList中是否有非空的span
    Span* it = list.Begin();

    while(it != list.End())
    {
        if(it->_freeList != nullptr)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }

    // 走到这说明需要从page cache中获取

    // 解除桶锁，方便thread cache释放内存回来不会被阻塞
    list._mtx.unlock();

    // 访问page cache之前需要加上其大锁
    PageCache::GetInstance()->_pageMtx.lock();
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    span->_isUse = true;
    span->_objSize = size;
    // 解掉大锁
    PageCache::GetInstance()->_pageMtx.unlock();

    // 将获取到的span进行切分
    // 先计算出其对应的起始和结束地址以及所占大块内存的大小
    char* start = (char*)(span->_pageId << PAGE_SHIFT);
    size_t bytes = span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    // 先切一块下来做头，方便尾插
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }

    NextObj(tail) = nullptr;
    
    // 将切分好的span挂到对应的链表中，然后加锁
    list.PushFront(span);
    list._mtx.lock();

    return span;
}


void CentralCache::ReleaseListToSpan(void* start, size_t size)
{
    assert(start);
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    while(start)
    {
        void* next = NextObj(start);

        // 先计算出该对象对应的span，然后再将其插入其中
        Span* span = PageCache::GetInstance()->MapObjToSpan(start);
        assert(span);
        assert(span->_freeList);
        NetxObj(start) = span->_freeList;
        span->_freeList = start;
        span->_useCount -= 1;

        // 当切分给thread cache的内存对象全部还回来时，证明该span也该还给page cache了
        if(span->_useCount == 0)
        {
            // 将该span从自由链表中剥离
            _spanLists[index].Erase(span);
            span->_freeList = nullptr;
            span->_prev = nullptr;
            span->_next = nullptr;

            // 解除桶锁，此时只使用page cache一把大锁即可
            _spanLists[index]._mtx.unlock();

            PageCache::GetInstance()->_pageMtx.lock();
            PageCache::GetInstance()->ReleaseSpanToPageCache(span);
            PageCache::GetInstance()->_pageMtx.unlock();

            // 加上桶锁
            _spanLists[index]._mtx.lock();
        }

        start = next;
    }

    // 解除桶锁
    _spanLists[index]._mtx.unlock();
}



size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size size)
{
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    Span* span = CentralCache::GetInstance()->GetInstance(_spanLists[index], size);
    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    end = start;
    size_t i = 0;
    size_t actualNum = 1;

    while(i < batchNum - 1 && NextObj(end) != nullptr)
    {
        i++;
        actualNum++;
        end = NextObj(end);
    }

    span->_freeList = NextObj(end);
    NextObj(end) = nullptr;
    span->_useCount = actualNum;

    // 解除桶锁
    _spanLists[index]._mtx.unlock();

    return actualNum;
}



Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    Span* it = list.Begin();

    while(it != list.End())
    {
        if(it->_freeList)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }

    list._mtx.unlock();

    PageCache::GetInstance()->_pageMtx.lock();
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    span->_isUse = true;
    span->_objSize = size;
    PageCache::GetInstance()->_pageMtx.unlock();

    char* start = (char*)(span->_pageId << PAGE_SHIFT);
    size_t bytes = span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }

    NextObj(tail) = nullptr;

    list.PushFront(span);
    list._mtx.lock();

    return span;
}


void CentralCache::ReleaseListToSpan(void* start, size_t size)
{
    assert(start);
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    while(start)
    {
        void* next = NextObj(start);

        Span* span = PageCache::GetInstance()->MapObjToSpan(start);
        assert(span);
        assert(span->_freeList);
        NextObj(start) = span->_freeList;
        span->_freeList = start;
        span->_useCount -= 1;

        if(span->_useCount == 0)
        {
            _spanLists[index].Erase(span);
            span->_freeList = nullptr;
            span->_prev = nullptr;
            span->_next = nullptr;

            _spanLists[index]._mtx.unlock();
            PageCache::GetInstance()->_pageMtx.lock();
            PageCache::GetInstance()->ReleaseSpanToPageCache(span);
            PageCache::GetInstance()->_pageMtx.unlock();
            _spanLists[index]._mtx.lock();
        }

        start = next;
    }

    // 解除桶锁
    _spanLists[index]._mtx.unlock();
}




size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    Span* span = CentralCache::GetInstance()->GetOneSpan(_spanLists[index], size);
    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    end = start;
    size_t i = 0;
    size_t actualNum = 1;

    while(i < batchNum - 1 && NextObj(end) != nullptr)
    {
        i++;
        actualNum++;
        end = NextObj(end);
    }

    span->_freeList = NextObj(end);
    NextObj(end) = nullptr;
    span->_useCount = actualNum;

    // 解除桶锁
    _spanLists[index]._mtx.unlock();

    return actualNum;
}



// 获取一个非空的span
Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    Span* it = list.Begin();

    while(it != list.End())
    {
        if(it->_freeList != nullptr)
        {
            return it;
        }
        else
        {
            it = it->_next;
        }
    }

    list._mtx.unlock();

    PageCache::GetInstance()->_pageMtx.lock();
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    span->_isUse = true;
    span->_objSize = size;
    PageCache::GetInstance()->_pageMtx.unlock();

    // 将获取到的span进行切分
    // 首先计算出其所对应的起始和结束地址以及所占的空间大小
    char* start = (char*)(span->_pageId << PAGE_SHIFT);
    size_t bytes = span->_ << PAGE_SHIFT;
    char* end = start + bytes;

    // 先切一块下来做头，方便尾插
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = NextObj(tail);
        start += size;
    }

    NextObj(tail) = nullptr;

    // 将切好的span挂到对应的链表中，然后加锁
    list.PushFront(span);
    list._mtx.lock();

    return span;
}


void CentralCache::ReleaseListToSpan(void* start, size_t size)
{
    assert(start);
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    while(start)
    {
        void* next = NextObj(start);

        // 首先计算出该对象对应的span，然后将其插入其中
        Span* span = PageCache::GetInstance()->MapObjToSpan(start);
        assert(span);
        assert(span->_freeList);
        NextObj(start) = span->_freeList;
        span->_freeList = start;
        span->_useCount -= 1;

        if(span->_useCount == 0)
        {
            // 此时说明分配给thread cache的内存对象全部还回来了，该span也可以还给系统堆了
            _spanLists[span->_n].Erase(span);
            span->_freeList = nullptr;
            span->_prev = nullptr;
            span->_next = nullptr;

            // 先解除桶锁，此时只使用page cache一把大锁即可
            _spanLists[index]._mtx.unlock();

            PageCache::GetInstance()->_pageMtx.lock();
            PageCache::GetInstance()->ReleaseSpanToPageCache(span);
            PageCache::GetInstance()->_pageMtx.unlock();

            _spanLists[index]._mtx.lock();
        }

        start = next;
    }

    // 解除桶锁
    _spanLists[index]._mtx.unlock();
}



// 获取一批内存对象给thread cache 
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    // 首先获取一个非空的span
    Span* span = CentralCache::GetInstance()->GetOneSpan(_spanLists[index], size);
    assert(span);
    assert(span->_freeList);

    start = span->_freeList;
    end = start;
    size_t i = 0;
    size_t actualNum = 1;

    while(i < batchNum - 1 && NextObj(end) != nullptr)
    {
        i++;
        actualNum++;
        end = NextObj(end);
    }

    span->_freeList = NextObj(end);
    NextObj(end) = nullptr;
    
    // 解除桶锁
    _spanLists[index]._mtx.unlock();

    return actualNum;
}

// 获取一个非空的span
Span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
    assert(size <= MAX_BYTES);

    // 首先检查当前的链表中是否有非空的span
    Span* it = list.Begin();
    while(it != list.End())
    {
        if(it->_freeList != nullptr)
        {
            return it;
        }
        else 
        {
            it = it->_next;
        }
    }

    // 走到这说明需要从page cache中获取span

    // 先解除桶锁，方便thread cache释放内存对象回来不会被阻塞
    list._mtx.unlock();

    PageCache::GetInstance()->_pageMtx.lock();
    Span* span = PageCache::GetInstance()->NewSpan(SizeClass::NumMovePage(size));
    assert(span);
    assert(span->_freeList);
    PageCache::GetInstance()->_pageMtx.unlock();

    // 对获取到的span进行切分
    // 首先计算出该span对应的起始和结束地址以及所占空间的大小
    char* start = (char*)span->_pageId << PAGE_SHIFT;
    size_t bytes = span->_n << PAGE_SHIFT;
    char* end = start + bytes;

    // 先切一块下来做头，方便尾插 - 尾插 - 提高缓存命中率
    span->_freeList = start;
    start += size;
    void* tail = span->_freeList;

    while(start < end)
    {
        NextObj(tail) = start;
        tail = start;
        start += size;
    }

    NetxObj(tail) = nullptr;

    // 将切好的span挂到对应的自由链表中，然后加锁
    list.PushFront(span);
    list._mtx.lock();

    return span;
}


void CentralCache::ReleaseListToSpan(void* start, size_t size)
{
    assert(start);
    assert(size <= MAX_BYTES);

    size_t index = SizeClass::Index(size);

    // 加上桶锁
    _spanLists[index]._mtx.lock();

    while(start != nullptr)
    {
        void* next = NextObj(start);

        // 首先计算出该对应对应的span
        Span* span = PageCache::GetInstance()->MapObjToSpan(start);
        assert(span);
        assert(span->_freeList);
        
        // 将该对象头插到该span中
        NetxObj(start) = span->_freeList;
        span->_freeList = start;
        span->_useCount -= 1;

        if(span->_useCount == 0)
        {
            // 此时表示span分配给thread cache使用的内存对象全部还回来了，该span也可以还给page cache了
            // 解除桶锁，此时只使用page cache一把大锁即可
            _spanLists[index]._mtx.unlock();
            PageCache::GetInstance()->_pageMtx.lock();
            PageCache::GetInstance()->ReleaseSpanToPageCache(span);
            PageCache::GetInstance()->_pageMtx.unlock();
            _spanLists[index]._mtx.lock();
        }

        start = next;
    }

    // 解除桶锁
    _spanLists[index]._mtx.unlock();
    
}


